package com.example.user.service.impl;

import com.example.common.redis.service.RedisService;
import com.example.common.util.constant.UserConstants;
import com.example.service.util.service.TokenService;
import com.example.common.util.enums.BusinessEnum;
import com.example.common.util.exception.BusinessException;
import com.example.common.util.utils.DateUtils;
import com.example.common.util.utils.StringUtils;
import com.example.common.util.utils.UniversalUtils;
import com.example.model.domain.entity.user.UserInfo;
import com.example.model.vo.user.LoginVo;
import com.example.model.vo.user.UserAuthVo;
import com.example.model.vo.user.UserInfoQueryVo;
import com.example.service.util.conversion.UserInfoConversion;
import com.example.user.mapper.UserInfoMapper;
import com.example.user.service.UserInfoService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 用户Service业务层处理
 *
 * @author ruoyi
 * @date 2021-07-15
 */
@Service
public class UserInfoServiceImpl implements UserInfoService
{
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private RedisService redisService;

    @Resource
    private TokenService tokenService;



    /*
    这个分页查询是为了这样用：
    如果传来的参数没有查询条件（也就是只有页码，页面大小），就是一个无条件查询返回分页
    有条件就根据条件查，但是它不是只供一个页面的接口使用，它是供多个页面使用
    所以就需要对每个参数进行判断，如果XXX不为空就执行XXX条件查询
     */
    @Override
    public PageInfo<UserInfo> getUserInfoPage(Integer pageNum, Integer pageSize, UserInfoQueryVo userInfoQueryVo) {

        //用户名称
        String name = userInfoQueryVo.getKeyword();//-- name
        Integer status = userInfoQueryVo.getStatus();//-- status
        Integer authStatus = userInfoQueryVo.getAuthStatus();//-- authStatus
        String createTimeBegin = userInfoQueryVo.getCreateTimeBegin();//-- createTime
        String createTimeEnd = userInfoQueryVo.getCreateTimeEnd();//-- updateTime
        //感觉上写成一个方法反而更麻烦
        if (StringUtils.isNotEmpty(name) || StringUtils.isNotEmpty(createTimeBegin) || StringUtils.isNotEmpty(createTimeEnd)
                || StringUtils.isNotNull(status) || StringUtils.isNotNull(authStatus)){
            PageHelper.startPage(pageNum,pageSize);
            List<UserInfo> userInfos = userInfoMapper.selectUserInfoPage(userInfoQueryVo);
            PageInfo<UserInfo> userInfoPageInfo = new PageInfo<>(userInfos);
            userInfoPageInfo.getList().forEach(this::patchUserInfo);
            return userInfoPageInfo;
        }
        PageHelper.startPage(pageNum,pageSize);
        List<UserInfo> userInfos = userInfoMapper.selectUserInfoList();
        userInfos.forEach(this::patchUserInfo);
        return new PageInfo<>(userInfos);
    }


    @Override
    public Integer lockedUserById(Long userId, Integer status) {
        return userInfoMapper.lockedUserById(userId, status);
    }


    @Override
    public Map<String, Object> getUserInfoDetailsById(Long userId) {
        HashMap<String, Object> result = new HashMap<>();
        UserInfo userInfo = this.patchUserInfo(userInfoMapper.selectUserInfoById(userId));
        result.put(UserConstants.USER_INFO,userInfo);
        //TODO  根据userid查询就诊人信息

        return result;
    }


    @Override
    public Integer approveUserInfoById(Long userId, Integer authStatus) {
        return userInfoMapper.approveUserInfoById(userId, authStatus);
    }


    @Override
    public Map<String, Object> login(LoginVo loginVo) {
        /*
        流程解析：
        前端发起登录请求传值，手机号验证码基本都会有（为空直接异常），如果验证码与redis里的相同且openid不为空（判断为已注册用户），更新用户登录信息（登录时间）
        如果openid为空（可能是新用户注册），
         */
        String phone = loginVo.getPhone();
        String code = loginVo.getCode();
        String openid = loginVo.getOpenid();
        UserInfo userInfo = null;
        if (StringUtils.isNotEmpty(phone) && StringUtils.isNotEmpty(code)){
            String redisCode = redisService.getCacheObject(loginVo.getPhone());
            //验证 验证码准确性
            if (Objects.equals(code,redisCode) && StringUtils.isNotEmpty(openid)){
                userInfo = userInfoMapper.selectUserInfoByOpenId(openid);
                if (StringUtils.isNotNull(userInfo)){
                    userInfo.setPhone(loginVo.getPhone());
                    userInfo.setUpdateTime(DateUtils.getNowDate());
                    userInfoMapper.updateUserInfo(userInfo);
                }else {
                    throw new BusinessException(BusinessEnum.CODE_ERROR);
                }
            }
            //userInfo为空就往下执行
            //判断手机号是否存在，存在就查询返回数据，不存在就注册
            if (StringUtils.isNull(userInfo)){
                userInfo = this.register(phone);
            }

            //是否禁用
            if (userInfo.getStatus().equals(UserConstants.STATUS_VALUE_NORMAL)){
                //不是第一次直接登录，返回登录信息，登录用户名，token
                HashMap<String, Object> result = new HashMap<>();
                result.put(UserConstants.NAME,userInfo.getNickName());
                String token = tokenService.getToken(userInfo.getId(), userInfo.getName());
                result.put(UserConstants.TOKEN,token);
                return result;
            }
            throw new BusinessException(BusinessEnum.USER_BAN);
        }
        throw new BusinessException(BusinessEnum.PARAM_ERROR);
    }



    @Override
    public Integer userAuth(Long userId, UserAuthVo userAuthVo) {
        UserInfo userInfo = userInfoMapper.selectUserInfoById(userId);
        //设置认证信息
        userInfo.setName(userAuthVo.getName());
        userInfo.setCertificatesType(userAuthVo.getCertificatesType());//证件类型
        userInfo.setCertificatesNo(userAuthVo.getCertificatesNo());//证件号
        userInfo.setCertificatesUrl(userAuthVo.getCertificatesUrl());//证件图片地址
        userInfo.setAuthStatus(UserConstants.AUTH_STATUS_VALUE_DO);
        return userInfoMapper.updateUserInfo(userInfo);
    }



    @Override
    public UserInfo getUserInfoById(Long userId) {
        return userInfoMapper.selectUserInfoById(userId);
    }


    @Override
    public UserInfo getUserInfoByOpenId(String openid) {
        return userInfoMapper.selectUserInfoByOpenId(openid);
    }


    @Override
    public Integer insertUserInfo(UserInfo userInfo) {
        return userInfoMapper.insertUserInfo(userInfo);
    }


    /**
     * 注册
     * @param phone
     * @return
     */
    private UserInfo register(String phone) {
        UserInfo userInfo = userInfoMapper.selectUserInfoByPhone(phone);
        if (StringUtils.isNull(userInfo)){
            //需要new一个新的，因为它是null
            userInfo = new UserInfo();
            userInfo.setPhone(phone);
            userInfo.setNickName(UniversalUtils.getEnglishRandomNickname(8));
            userInfo.setName(userInfo.getNickName());
            userInfo.setStatus(UserConstants.STATUS_VALUE_NORMAL);
            //此处奇怪了，数据库配置的有默认值，xml文件里也没加非空判断，但是不让为空
            userInfo.setAuthStatus(UserConstants.AUTH_STATUS_VALUE_DO);
            userInfo.setCreateTime(DateUtils.getNowDate());
            userInfo.setUpdateTime(userInfo.getCreateTime());
            userInfo.setDeleted(UserConstants.DELETED_VALUE);
            userInfoMapper.insertUserInfo(userInfo);
        }
        return userInfo;
    }


    /**
     * 编号转值
     * @param userInfo
     */
    private UserInfo patchUserInfo(UserInfo userInfo) {
        //状态抓换，（数字转汉字）
        userInfo.getParam().put(UserConstants.AUTH_STATUS_STRING, UserInfoConversion.stateTransition(userInfo.getStatus()));
        //用户状态
        String statsString = userInfo.getStatus() == 0 ? UserConstants.LOCKED_ZN : UserConstants.NORMAL_ZN;
        userInfo.getParam().put(UserConstants.STATUS_STRING,statsString);
        return userInfo;
    }


}
